////////////////////////////////////////////////////////////////////
// Programme de compression/décompression DRP pour Chrono Cross
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
// Nemesis pour Terminus Traduction (tt_nemesis@yahoo.fr)
// Date de création :		05/08/03
// Dernière modification :	06/08/03
////////////////////////////////////////////////////////////////////

// Entete
#include "Drp.h"

// Type de données pour les fichiers
typedef struct {
	char *nom;
	int num;
} Drp_TFich;

// Noms des fichiers
Drp_TFich Drp_Outs[DRP_FICHS_NB];
_int16 Drp_Outs_Nb;

/*------------------------------------------------------------------
  Initialisation des fichiers du DRP
--------------------------------------------------------------------
 <- dir : chemin partiel des infos à charger
 <- fich : fichier d'infos à charger
------------------------------------------------------------------*/
void Drp_Infos (char *dir, char *fich)
{
	// Fichier des infos
	FILE *infos_f;
	// Nom de l'iso (chemin)
	char infos_nom[DRP_NOM_MAX];
	// Numero de fichier
	int fich_deb,fich_fin,f;
	// Nom de fichier
	char fich_nom_complet[DRP_FICHS_NOM];
	char fich_nom[DRP_FICHS_NOM];
	char fich_ext[4];
	// Ligne
	char ligne[DRP_LIGNE_MAX];
	// Nombre de champs d'infos
	int result;

	// Ouverture du fichier des infos principales
	sprintf(infos_nom,"%s%s%s%s.%s",
		DIR_INFOS,DIR_INFOS_DRP,dir,fich,EXT_INFOS);
	infos_f=fopen(infos_nom,"rb");

	if (infos_f==NULL)
		Main_Message_S("Erreur d'ouverture des infos.\n","",ER);
	else {
		// Réinitialisation
		Drp_Outs_Nb=0;
		// Récupération des noms de fichiers
		while (fgets(ligne,DRP_LIGNE_MAX,infos_f)!=NULL)
			// Cas d'un commentaire ou d'un blanc
			if (ligne[0]!=COMMENT) {
				result=sscanf(ligne,"%d-%d %3s %s",
					&fich_deb,&fich_fin,fich_ext,fich_nom);
				switch (result) {
				case 4:
					sprintf(fich_nom_complet,
						" (%s).%s",fich_nom,fich_ext);
					break;
				case 3:
					sprintf(fich_nom_complet,
						".%s",fich_ext);
					break;
				case 2:
					sprintf(fich_nom_complet,
						".%s",EXT_DUMP);
					break;
				default:
					Main_Message_S("Info erronee... ","",ER);
				}
				if (result>1)
					for(f=fich_deb;f<=fich_fin;f++) {
						Drp_Outs[Drp_Outs_Nb].nom=strdup(fich_nom_complet);
						Drp_Outs[Drp_Outs_Nb].num=f;
						Drp_Outs_Nb++;
					}
			}
		// Fermeture du fichier des infos
		fclose(infos_f);
	}
}

/*------------------------------------------------------------------
  Réinitialisation des infos des DRP à NULL
------------------------------------------------------------------*/
void Drp_Infos_Vide (void)
{
	int f;

	for(f=0;f<DRP_FICHS_NB;f++)
		if (Drp_Outs[f].nom!=NULL) {
			free(Drp_Outs[f].nom);
			Drp_Outs[f].nom=NULL;
		}
}

/*------------------------------------------------------------------
  Décompression DRP d'un fichier
--------------------------------------------------------------------
 <- dir : dossier du fichier DRP à décompresser
 <- fich : fichier DRP à décompresser (sans extension pour dossier)
------------------------------------------------------------------*/
void Drp_Decompression (char *dir, int fich)
{
	// Fichier Drp à décompresser
	FILE *drp_f;
	char drp_nom[DRP_NOM_MAX];
	char *drp_nom2;
	char drp_nom_complet[DRP_NOM_MAX];
	// Fichier de sortie
	FILE *out_f;
	char out_nom[DRP_NOM_MAX];
	// Nom du dossier
	char dossier[DRP_NOM_MAX];
	// Adresses des fichiers
	_int32 adresses[DRP_FICHS_NB];
	int adresses_nb=-1;
	// Index des fichiers
	int f;
	// Position d'arrêt de copie
	_int32 pos;
	// Buffer
	char buffer[DRP_BUFFER];

	// Recherche du fichier DRP
	sprintf(drp_nom,"%04d",fich);
	sprintf(dossier,"%s%s",DIR_FICH_IN,dir);
	Fichier_Cherche(dossier,drp_nom,EXT_DRP,&drp_nom2);
	sprintf(drp_nom_complet,"%s%s",dossier,drp_nom2);
	// Ouverture du fichier DRP
	drp_f=fopen(drp_nom_complet,"rb");

	// Fichier existant ?
	if (drp_f==NULL)
		Main_Message_S("Impossible d'ouvrir le fichier.\n","",ER);
	else {
		// Chargement des paramètres de décompression
		Drp_Infos(dir,drp_nom);
		// Creation du dossier (s'il n'existe pas déjà)
		sprintf(dossier,"%s%s%s%s\\",
			DIR_FICH_IN,dir,ENT_DOSSIER,drp_nom);
		mkdir(dossier);
		// Saut de l'entête
		fseek(drp_f,DRP_ENTETE,SEEK_SET);
		// Chargement des adresses
		do {
			adresses_nb++;
			fread(&adresses[adresses_nb],sizeof(_int32),1,drp_f);
		} while(adresses[adresses_nb]!=0);
		// Modification pour la dernière adresse
		fseek(drp_f,0L,SEEK_END);
		adresses[adresses_nb]=ftell(drp_f);
		// Décompression des fichiers
		for(f=0;f<Drp_Outs_Nb && f<adresses_nb;f++) {
			// Ouverture du fichier extrait
			sprintf(out_nom,"%s%04d%s",dossier,f,Drp_Outs[f].nom);
			out_f=fopen(out_nom,"wb");
			if (out_f==NULL)
				Main_Message_S("Impossible d'extraire.\n","",ER);
			else {
				// Placement dans le fichier compacté
				// /!\ On doit sauter la description du fichier /!\
				// Je m'étais fait avoir dans les versions
				// précédentes :(
				fseek(drp_f,adresses[Drp_Outs[f].num]+DRP_DESCR,SEEK_SET);
				// Extraction du fichier
				for(pos=adresses[Drp_Outs[f].num]+DRP_DESCR;
					pos<=adresses[Drp_Outs[f].num+1]-DRP_BUFFER;
					pos+=DRP_BUFFER)
				{
					fread(buffer,sizeof(char),DRP_BUFFER,drp_f);
					fwrite(&buffer,sizeof(char),DRP_BUFFER,out_f);
				}
				// Attention à l'ordre pour
				// rester dans les positifs
				pos=(adresses[Drp_Outs[f].num+1]
					-adresses[Drp_Outs[f].num]-DRP_DESCR)
					%DRP_BUFFER;
				fread(buffer,sizeof(char),pos,drp_f);
				fwrite(&buffer,sizeof(char),pos,out_f);
				// Fermeture du fichier extrait
				fclose(out_f);
			}
		}
		// Fermeture du DRP
		fclose(drp_f);
		// Nettoyage des infos drp
		Drp_Infos_Vide();
	}
}

/*------------------------------------------------------------------
  DéDRPage d'un ensemble de fichiers
--------------------------------------------------------------------
 <- fich = ensemble des fichiers déterminés par des délimiteurs
	exemple : 1-4;5;8 = fichiers 1->5 + 8
------------------------------------------------------------------*/
void Drp_D_Exec (char* fich) {
	// Numéros des fichiers à décompacter
	char* fichs_intervals[DRP_FICHS_INTER];
	int interval,i;
	// Type d'intervalle
	int result;
	// Bornes
	unsigned _int16 fich_deb,fich_fin,r;
	// Dossier/fichiers
	char* dossier;
	char* fichiers;

	Main_Message_S("Decompression DRP de %s... ",fich,OK);

	// Décomposition dossier/fichiers
	dossier=strtok(fich,SEPARATEUR);
	if (dossier[0]==NEUTRE)
		dossier[0]=0;
	fichiers=strtok(NULL,SEPARATEUR);
	
	// Décomposition des rooms en intervalles
	interval=0; // intervalle actuel
	fichs_intervals[interval]=strtok(fichiers,";");
	do
		interval++;
	while((fichs_intervals[interval]=strtok(NULL,";"))!=NULL);

	// Extension des intervalles
	for(i=0;i<interval;i++) {
		result=sscanf(fichs_intervals[i],"%d-%d",
			&fich_deb,&fich_fin);
		switch (result) {
		case 1:
			Drp_Decompression(dossier,fich_deb);
			break;
		case 2:
			for (r=fich_deb;r<=fich_fin;r++)
				Drp_Decompression(dossier,r);
			break;
		default:
			Main_Message_D("Erreur dans l'intervalle %d.\n",i+1,ER);
		}
	}
	Main_OK();
}

/*------------------------------------------------------------------
  Compression DRP de fichiers
--------------------------------------------------------------------
 <- dir : dossier du fichier DRP à compresser
 <- fich : fichier DRP à décompresser (sans extension pour dossier)
------------------------------------------------------------------*/
void Drp_Compression (char *dir, int fich)
{
	// Fichier Drp à décompresser
	FILE *drp_in_f,*drp_out_f;
	char drp_nom[DRP_NOM_MAX];
	char *drp_nom2;
	char drp_nom_complet[DRP_NOM_MAX];
	// Fichiers d'entrée
	FILE *in_f;
	char in_nom[DRP_NOM_MAX];
	// Nom du dossier
	char dossier[DRP_NOM_MAX];
	// Adresse d'un fichier
	unsigned _int32 adresse;
	// Index des fichiers
	int f;
	// Buffer
	char buffer[DRP_BUFFER];
	// Entete du fichier DRP
	char entete[DRP_ENTETE];
	// Nombre d'octets lus
	int result;
	// Adresses du fichier original
	_int32 adresses[DRP_FICHS_NB];

	// Recherche du fichier DRP
	sprintf(drp_nom,"%04d",fich);
	sprintf(dossier,"%s%s",DIR_FICH_IN,dir);
	Fichier_Cherche(dossier,drp_nom,EXT_DRP,&drp_nom2);
	// Ouverture du fichier DRP d'entrée
	sprintf(drp_nom_complet,"%s%s",dossier,drp_nom2);
	drp_in_f=fopen(drp_nom_complet,"rb");

	// Fichier existant ?
	if (drp_in_f==NULL)
		Main_Message_S("Impossible d'ouvrir le fichier.\n","",ER);
	else {
		// Ouverture du fichier DRP de sortie
		sprintf(dossier,"%s%s",DIR_FICH_OUT,dir);
		sprintf(drp_nom_complet,"%s%s",dossier,drp_nom2);
		drp_out_f=fopen(drp_nom_complet,"wb");
		// Chargement des paramètres de décompression
		Drp_Infos(dir,drp_nom);
		// Copie du début d'entête de l'original
		fread(entete,sizeof(char),DRP_ENTETE,drp_in_f);
		fwrite(entete,sizeof(char),DRP_ENTETE,drp_out_f);
		// Accès au dossier
		sprintf(dossier,"%s%s%s%s\\",
			DIR_FICH_OUT,dir,ENT_DOSSIER,drp_nom);
		// Lecture de la première adresse originale
		fread(&adresses[0],sizeof(_int32),1,drp_in_f);
		// Enregistrement des adresses
		adresse=Drp_Outs_Nb*sizeof(_int32)+DRP_ENTETE;
		for(f=0;f<Drp_Outs_Nb;f++) {
			// Ecriture de l'adresse du fichier
			fwrite(&adresse,sizeof(_int32),1,drp_out_f);
			// Lecture de l'adresse originale
			fread(&adresses[f+1],sizeof(_int32),1,drp_in_f);
			// Ouverture du fichier à réinsérer
			sprintf(in_nom,"%s%04d%s",dossier,f,Drp_Outs[f].nom);
			// Completion du fichier source
			Fichier_Completer(in_nom);
			// Chargement des informations
			in_f=fopen(in_nom,"rb");
			fseek(in_f,0L,SEEK_END);
			// Attention bis à la description du fichier cf dump
			adresse+=ftell(in_f)+DRP_DESCR;
			fclose(in_f);
		};
		// Recompression des fichiers
		for(f=0;f<Drp_Outs_Nb;f++) {
			// Placement dans l'original
			fseek(drp_in_f,adresses[f],SEEK_SET);
			// Recopie d'entête de fichier de l'original
			fread(entete,sizeof(char),DRP_DESCR,drp_in_f);
			fwrite(entete,sizeof(char),DRP_DESCR,drp_out_f);
			// Ouverture du fichier à réinsérer
			sprintf(in_nom,"%s%04d%s",dossier,f,Drp_Outs[f].nom);
			in_f=fopen(in_nom,"rb");
			if (in_f==NULL)
				Main_Message_S("Impossible d'inserer.\n","",ER);
			else {
				// Copie des données
				while((result=fread(buffer,sizeof(char),
					DRP_BUFFER,in_f))>0)
					fwrite(&buffer,sizeof(char),result,drp_out_f);
				// Fermeture du fichier extrait
				fclose(in_f);
			}
		}
		// Fermeture des fichiers
		fclose(drp_in_f);
		fclose(drp_out_f);
		// Nettoyage des infos drp
		Drp_Infos_Vide();
	}
}

/*------------------------------------------------------------------
  ReDRPage d'un ensemble de fichiers
--------------------------------------------------------------------
 <- fich = ensemble des fichiers déterminés par des délimiteurs
	exemple : 1-4;5;8 = fichiers 1->5 + 8
------------------------------------------------------------------*/
void Drp_C_Exec (char* fich) {
	// Numéros des fichiers à recompacter
	char* fichs_intervals[DRP_FICHS_INTER];
	int interval,i;
	// Type d'intervalle
	int result;
	// Bornes
	unsigned _int16 fich_deb,fich_fin,r;
	// Dossier/fichiers
	char* dossier;
	char* fichiers;

	Main_Message_S("Compression DRP de %s... ",fich,OK);

	// Décomposition dossier/fichiers
	dossier=strtok(fich,SEPARATEUR);
	if (dossier[0]==NEUTRE)
		dossier[0]=0;
	fichiers=strtok(NULL,SEPARATEUR);
	
	// Décomposition des rooms en intervalles
	interval=0; // intervalle actuel
	fichs_intervals[interval]=strtok(fichiers,";");
	do
		interval++;
	while((fichs_intervals[interval]=strtok(NULL,";"))!=NULL);

	// Extension des intervalles
	for(i=0;i<interval;i++) {
		result=sscanf(fichs_intervals[i],"%d-%d",
			&fich_deb,&fich_fin);
		switch (result) {
		case 1:
			Drp_Compression(dossier,fich_deb);
			break;
		case 2:
			for (r=fich_deb;r<=fich_fin;r++)
				Drp_Compression(dossier,r);
			break;
		default:
			Main_Message_D("Erreur dans l'intervalle %d.\n",i+1,ER);
		}
	}
	Main_OK();
}
